/*
 * Game.c
 *
 *  Created on: 2012-8-16
 *      Author: zhangchao
 */

#include<Chess.h>
#include<Game.h>

void initGame() {
	/* own */
	initOneSideArray(true);
	/* competitor */
	initOneSideArray(false);

}

void initOneSideArray(bool isOwn) {
	int loopIndex;

	/* bin */
	for (loopIndex = 0; loopIndex < 5; loopIndex++) {
		initChess(CHESS_BIN, 1 + loopIndex * 2, calYIndexBySide(4, isOwn));
	}

	/* pao */
	initChess(CHESS_PAO, 2, calYIndexBySide(3, isOwn));
	initChess(CHESS_PAO, 8, calYIndexBySide(3, isOwn));

	/* ju */
	initChess(CHESS_JU, 1, calYIndexBySide(1, isOwn));
	initChess(CHESS_JU, 9, calYIndexBySide(1, isOwn));

	/* ma */
	initChess(CHESS_MA, 2, calYIndexBySide(1, isOwn));
	initChess(CHESS_MA, 8, calYIndexBySide(1, isOwn));

	/* xiang */
	initChess(CHESS_XIANG, 3, calYIndexBySide(1, isOwn));
	initChess(CHESS_XIANG, 7, calYIndexBySide(1, isOwn));

	/* shi */
	initChess(CHESS_SHI, 4, calYIndexBySide(1, isOwn));
	initChess(CHESS_SHI, 6, calYIndexBySide(1, isOwn));

	/* jiang */
	initChess(CHESS_SHUAI, 5, calYIndexBySide(1, isOwn));

}

int calYIndexBySide(int ownIndex, bool isOwn) {
	if (isOwn) {
		return ownIndex;
	} else {
		return INDEX_Y_MAX + 1 - ownIndex;
	}
}

void initChess(char type, int xIndex, int yIndex) {

	char chess = 0;
	if (yIndex > 5) {
		chess = chess | 128;
	}
	chess = chess | (type << 4);

	board[xIndex][yIndex] = chess;
}

int calNextStep(int competitorStep,int cpuCoreNum,int os) {
	int step;
	int maxOwnSide = MIN_CHESS_VAL_SUM;
	int minCompetitorSide = MAX_CHESS_VAL_SUM;
	int round = 0;

	if (competitorStep != 0) {
		changeBoardByStep(board, competitorStep);
		if (canBeFinished(board, OWN_SIDE)) {
			return LOSE_FLAG;
		}
	}

	findOwnStep(board, &maxOwnSide, &minCompetitorSide, &round, &step);

	changeBoardByStep(board, step);

	if(maxOwnSide==MIN_CHESS_VAL_SUM){
		return WIN_FLAG;
	}

	return step;
}

int findOwnStep(int currentBoard[][], int *maxOwnSide, int *minCompetitorSide,
		int *round, int *bestStep) {

	int stepCnt = 0;
	int steps[];
	int i;
	int newBoard[][];
	int boardValue;
	int bestNextBoardVal = MIN_CHESS_VAL_SUM;
	int tmpBestStep;

	if (*round > MAX_ROUND_NUM) {
		return evaluate(currentBoard);
	}

	steps = getAllPossibleStep(currentBoard, &stepCnt);

	for (i = 0; i < stepCnt; i++) {
		newBoard = copyArray(board, INDEX_X_MAX + 1, INDEX_Y_MAX + 1);
		changeBoardByStep(newBoard, steps[i]);

		if(canBeFinished(newBoard,OWN_SIDE)){
			continue;
		}

		boardValue = findCmpStep(newBoard, maxOwnSide, minCompetitorSide, round,
				&tmpBestStep);

		if (boardValue > bestNextBoardVal) {
			bestNextBoardVal = boardValue;
			bestStep = tmpBestStep;
		}

		if (bestNextBoardVal < *minCompetitorSide) {
			break;
		}
	}

	if (bestNextBoardVal > *minCompetitorSide) {
		*minCompetitorSide = bestNextBoardVal;
	}
	return bestNextBoardVal;

}

char* copyArray(char array[][], int xcnt, int ycnt) {
	char newArray[xcnt][ycnt];
	int indexX, indexY;

	for (indexX = 0; indexX < xcnt; indexX++)
		for (indexY = 0; indexY < ycnt; indexY++) {
			newArray[indexX][indexY] = array[indexX][indexY];
		}

	return newArray;

}

//char* reveseBoard(char currentBoard[][], int xcnt, int ycnt) {
//	char newBoard[xcnt][ycnt];
//	int indexX, indexY;
//
//	for (indexX = 0; indexX < xcnt; indexX++)
//		for (indexY = 0; indexY < ycnt; indexY++) {
//			newBoard[xcnt - 1 - indexX][ycnt - 1 - indexY] =
//					currentBoard[indexX][indexY];
//		}
//
//	return newBoard;
//}
//
//int reveseStep(int step) {
//	int oldIndexX, oldIndexY, indexX, indexY;
//
//	cutStepIntToParam(step, &oldIndexX, &oldIndexY, &indexX, &indexY);
//	return makeStepIntByParam(step, INDEX_X_MAX - oldIndexX,
//			INDEX_Y_MAX - oldIndexY, INDEX_X_MAX - indexX, INDEX_X_MAX - indexY);
//}

int findCmpStep(int currentBoard[][], int *maxOwnSide, int *minCompetitorSide,
		int *round, int *bestStep) {

	int stepCnt = 0;
	int steps[];
	int i;
	int newBoard[][];
	int boardValue;
	int bestNextBoardVal = MAX_CHESS_VAL_SUM;
	int tmpBestStep;

	steps = getAllPossibleStep(currentBoard,&stepCnt);

	for (i = 0; i < stepCnt; i++) {
		newBoard = copyArray(board, INDEX_X_MAX + 1, INDEX_Y_MAX + 1);
		changeBoardByStep(newBoard, steps[i]);

		if(canBeFinished(newBoard,COMP_SIDE)){
			continue;
		}

		boardValue = findOwnStep(newBoard, maxOwnSide, minCompetitorSide, round,
				&tmpBestStep);
		if (boardValue < bestNextBoardVal) {
			bestNextBoardVal = boardValue;
			bestStep = tmpBestStep;
		}
		if (bestNextBoardVal > *maxOwnSide) {
			break;
		}
	}

	if (bestNextBoardVal < *maxOwnSide) {
		*maxOwnSide = bestNextBoardVal;
	}

	(*round)++;

	return bestNextBoardVal;

}

bool changeBoardByStep(int currentBoard[][], int step) {
	int oldIndexX;
	int oldIndexY;
	int indexX;
	int indexY;
	char side;
	char type;
	char newPosSide;
	char newPosType;

	cutStepIntToParam(step, &oldIndexX, &oldIndexY, &indexX, &indexY);

	char chess = currentBoard[oldIndexX][oldIndexY];
	char newPos = currentBoard[indexX][indexY];
	if (newPos == 0) {
		currentBoard[indexX][indexY] = chess;
		currentBoard[oldIndexX][oldIndexY] = 0;
		return true;
	}

	getChessTypeAndSide(chess, &type, &side);
	getChessTypeAndSide(chess, &newPosType, &newPosSide);
	if (side == newPosSide) {
		return false;
	}

	currentBoard[indexX][indexY] = chess;
	currentBoard[oldIndexX][oldIndexY] = 0;
	return true;
}

int makeStepIntByParam(int oldIndexX, int oldIndexY, int indexX, int indexY) {
	int result;

	/*前4位为棋子的原X轴坐标*/
	result = oldIndexX;

	/*第2个4位为棋子的原Y轴坐标*/
	result = result << 4;
	result = result | oldIndexY;

	/*第3个4位为棋子的新X轴坐标 */
	result = result << 4;
	result = result | indexX;

	/*后4位为新Y轴坐标*/
	result = result << 4;
	result = result | indexY;

	return result;
}

void cutStepIntToParam(int step, int *oldIndexX, int *oldIndexY, int *indexX,
		int *indexY) {
	*indexY = step & 15;
	*indexX = (step >> 4) & 15;
	*oldIndexY = (step >> 8) & 15;
	*oldIndexX = (step >> 12) & 15;
}

